//
// Created by pulsarv on 19-12-8.
//



#ifndef MOBILESEARCH_INPUT_WRAPPERS_H
#define MOBILESEARCH_INPUT_WRAPPERS_H
#include <utility>
#include <list>
#include <memory>
#include <set>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <opencv2/opencv.hpp>
namespace MobileSearch {

    class InputChannel;

    class IInputSource {
    public:
        virtual bool read(cv::Mat &mat, const std::shared_ptr<InputChannel> &caller) = 0;

        virtual void addSubscriber(const std::weak_ptr<InputChannel> &inputChannel) = 0;

        virtual cv::Size getSize() = 0;

        virtual void lock() {
            sourceLock.lock();
        }

        virtual void unlock() {
            sourceLock.unlock();
        }

        virtual ~IInputSource() = default;

    private:
        std::mutex sourceLock;
    };

    class InputChannel : public std::enable_shared_from_this<InputChannel> {  // note: public inheritance
    public:
        InputChannel(const InputChannel &) = delete;

        InputChannel &operator=(const InputChannel &) = delete;

        static std::shared_ptr<InputChannel> create(const std::shared_ptr<IInputSource> &source);

        bool read(cv::Mat &mat);

        void push(const cv::Mat &mat);

        cv::Size getSize();

    private:
        explicit InputChannel(std::shared_ptr<IInputSource> source) : source{std::move(source)} {}

        std::shared_ptr<IInputSource> source;
        std::queue<cv::Mat, std::list<cv::Mat>> readQueue;
        std::mutex readQueueMutex;
    };

    class VideoCaptureSource : public IInputSource {
    public:
        VideoCaptureSource(const cv::VideoCapture &videoCapture, bool loop);

        bool read(cv::Mat &mat, const std::shared_ptr<InputChannel> &caller) override;

        void addSubscriber(const std::weak_ptr<InputChannel> &inputChannel) override;

        cv::Size getSize() override;

    private:
        std::vector<std::weak_ptr<InputChannel>> subscribedInputChannels;
        cv::VideoCapture videoCapture;
        bool loop;
        cv::Size imSize;
    };
}

#endif